﻿using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

namespace DataLoad.iContact.WinClient
{
	/// <summary>
	/// SymmCrypto is a wrapper of System.Security.Cryptography.SymmetricAlgorithm classes
	/// and simplifies the interface. It supports customized SymmetricAlgorithm as well.
	/// </summary>
    internal class Encryptor
    {
		/// <remarks>
		/// Supported .Net intrinsic SymmetricAlgorithm classes.
		/// </remarks>
		public enum SymmProvEnum : int
		{
			DES, RC2, Rijndael
		}

		private SymmetricAlgorithm mobjCryptoService;

		/// <remarks>
		/// Constructor for using an intrinsic .Net SymmetricAlgorithm class.
		/// </remarks>
		public Encryptor(SymmProvEnum NetSelected)
		{
			switch (NetSelected)
			{
				case SymmProvEnum.DES:
					mobjCryptoService = new DESCryptoServiceProvider();
					break;
				case SymmProvEnum.RC2:
					mobjCryptoService = new RC2CryptoServiceProvider();
					break;
				case SymmProvEnum.Rijndael:
					mobjCryptoService = new RijndaelManaged();
					break;
			}
		}

		/// <remarks>
		/// Constructor for using a customized SymmetricAlgorithm class.
		/// </remarks>
		public Encryptor(SymmetricAlgorithm ServiceProvider)
		{
			mobjCryptoService = ServiceProvider;
		}

		private byte[] GetLegalKey(string Key)
		{
			string sTemp = Key;
			mobjCryptoService.GenerateKey();
			byte[] bytTemp = mobjCryptoService.Key;
			int KeyLength = bytTemp.Length;
			if (sTemp.Length > KeyLength)
				sTemp = sTemp.Substring(0, KeyLength);
			else if (sTemp.Length < KeyLength)
				sTemp = sTemp.PadRight(KeyLength, ' ');

			return ASCIIEncoding.ASCII.GetBytes(sTemp);
		}

		private byte[] GetLegalIV()
		{
			// The initial string of IV may be modified with any data you like
			string sTemp = "DataLoadGoolgeContacts";
			mobjCryptoService.GenerateIV();
			byte[] bytTemp = mobjCryptoService.IV;
			int IVLength = bytTemp.Length;
			if (sTemp.Length > IVLength)
				sTemp = sTemp.Substring(0, IVLength);
			else if (sTemp.Length < IVLength)
				sTemp = sTemp.PadRight(IVLength, ' ');

			return ASCIIEncoding.ASCII.GetBytes(sTemp);
		}

		public string Encrypting(string Source, string Key)
		{
			// use UTF8 unicode conversion for two byte characters
			byte[] bytIn = UTF8Encoding.UTF8.GetBytes(Source);

			// create a MemoryStream so that the process can be done without I/O files
			System.IO.MemoryStream ms = new System.IO.MemoryStream();

			// set the private key
			mobjCryptoService.Key = GetLegalKey(Key);
			mobjCryptoService.IV = GetLegalIV();

			// create an Encryptor from the Provider Service instance
			ICryptoTransform encrypto = mobjCryptoService.CreateEncryptor();

			// create Crypto Stream that transforms a stream using the encryption
			CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write);

			// write out encrypted content into MemoryStream
			cs.Write(bytIn, 0, bytIn.Length);
			cs.FlushFinalBlock();

			ms.Close();
			byte[] bytOut = ms.ToArray();

			// convert into Base64 so that the result can be used in xml
			return System.Convert.ToBase64String(bytOut);
		}

		public string Decrypting(string Source, string Key)
		{
			// convert from Base64 to binary
			byte[] bytIn = System.Convert.FromBase64String(Source);
			// create a MemoryStream with the input
			System.IO.MemoryStream ms = new System.IO.MemoryStream(bytIn, 0, bytIn.Length);

			// set the private key
			mobjCryptoService.Key = GetLegalKey(Key);
			mobjCryptoService.IV = GetLegalIV();

			// create a Decryptor from the Provider Service instance
			ICryptoTransform encrypto = mobjCryptoService.CreateDecryptor();

			// create Crypto Stream that transforms a stream using the decryption
			CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read);
			
			// read out the result from the Crypto Stream
			System.IO.StreamReader sr = new System.IO.StreamReader( cs );
			return sr.ReadToEnd();
		}
	}
}
